using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Windows.Forms;
using Microsoft.VSPowerToys.PackInstaller;
using NUnit.Framework;
using NUnit.Extensions.Forms;

namespace GUITestScenarios
{
    [TestFixture]
    public class VSActiveTests : NUnitFormTest
    {
        private PackInstallerForm packInstallForm;
        private ErrorMessages errorMessages;
        private string buttonName;
        private string messageFormName = "VisualStudioDetectedForm";
        private Process vsProcess;

        [TestFixtureSetUp]
        public void Init()
        {
            Process[] visualStudioProcesses = Process.GetProcessesByName("devenv");
            TextWriter errorWriter = Console.Error;
            if (visualStudioProcesses.Length != 0)
            {
                errorWriter.WriteLine("You must close Visual Studio before running the test suite.");
                Assert.IsTrue(false);
            }

            DialogResult dialogResult = MessageBox.Show("The Visual Studio Active tests will not pass if authentication is required. Click OK to continue or Cancel to skip the tests.", "No Visual Studio Authentication", MessageBoxButtons.OKCancel, MessageBoxIcon.Information);
            if (dialogResult != DialogResult.OK)
            {
                errorWriter.WriteLine("User clicked Cancel in response to No Visual Studio Authentication message.");
                Console.WriteLine("User clicked Cancel in response to No Visual Studio Authentication message.");
                Assert.AreEqual(DialogResult.OK, dialogResult);
            }

        }

        // Normally, this would be tagged with the [SetUp] attribute.
        // We removed it because, for some unknown reason, NUnitForms throws a
        // null reference exception when this is [SetUp]. However, everythign works fine
        // if the tests actively CALL TestSetup()
        public void TestSetup()
        {
            vsProcess = new Process();
            vsProcess.StartInfo.FileName = Path.Combine(Environment.ExpandEnvironmentVariables("%ProgramFiles%"),
                @"Microsoft Visual Studio 8\Common7\IDE\devenv.exe");
            // Start Visual Studio
            Assert.IsTrue(vsProcess.Start(), "devenv could not be started");
            // Wait for it to load
            System.Threading.Thread.Sleep(10000);
            vsProcess.WaitForInputIdle(10000);
            // Make sure it's alive
            Assert.IsTrue(vsProcess.Responding, "Visual Studio is not responding.");
        }

        [TearDown]
        public void TestTearDown()
        {
            if (vsProcess != null && vsProcess.HasExited == false)
            {
                vsProcess.Kill();
            }
            System.Threading.Thread.Sleep(10000);
        }

        public void GenericFormHandler()
        {

        }

        [Test]
        public void VSActiveContinueTest()
        {
            TestSetup();
            errorMessages = new ErrorMessages();
            // We have to set the expected form name and its handler before instantiating 
            // PackInstallerForm because the check for VS running and showing the related 
            // message box are done in the constructor

            ExpectModal(messageFormName, "MessageFormButtonClicker");
            buttonName = "continueButton";

            packInstallForm = new PackInstallerForm(String.Empty);

            // Set up the call back that has the test logic
            packInstallForm.OnPacksLoaded += new EventHandler<EventArgs>(ProcessButtonHandler);

            // Set the generic PackInstallerForm form handler  
            ExpectModal("PackInstallerForm", "GenericFormHandler");
            packInstallForm.ShowDialog();
            
            if (vsProcess.HasExited)
                errorMessages.Add("Visual Studio exitted after clicking " + buttonName + " button.");
            errorMessages.printErrors("VSActiveTest");
            Assert.AreEqual(0, errorMessages.Count, "VSActiveTest failed. Check Console output for error messages.");
        }

        [Test]
        public void VSActiveCloseVSTest()
        {
            TestSetup();
            errorMessages = new ErrorMessages();
            buttonName = "closeVisualStudioButton";
            // We have to set the expected form name and its handler before instantiating 
            // PackInstallerForm because the check for VS running and showing the related 
            // message box are done in the constructor
            ExpectModal(messageFormName, "MessageFormButtonClicker");

            packInstallForm = new PackInstallerForm(String.Empty);

            // Set up the call back that has the test logic
            packInstallForm.OnPacksLoaded += new EventHandler<EventArgs>(ProcessButtonHandler);

            // Set the generic PackInstallerForm form handler  
            ExpectModal("PackInstallerForm", "GenericFormHandler");
            packInstallForm.ShowDialog();

            // Sleep for 15 seconds to give VS time to close 
            System.Threading.Thread.Sleep(15000);

            if (vsProcess.HasExited == false)
                errorMessages.Add("Visual Studio did NOT exit after clicking " + buttonName + " button.");
            errorMessages.printErrors("VSActiveCloseVSTest");
            Assert.AreEqual(0, errorMessages.Count, "VSActiveCloseVSTest failed. Check Console output for error messages.");
        }

        [Test]
        public void VSActiveCancelTest()
        {
            errorMessages = new ErrorMessages();
            TestSetup();
            buttonName = "exitButton";

            // We have to set the expected form name and its handler before instantiating 
            // PackInstallerForm because the check for VS running and showing the related 
            // message box are done in the constructor

            ExpectModal(messageFormName, "MessageFormButtonClicker");
            packInstallForm = new PackInstallerForm(String.Empty);

            // If the cancel option works, we should not see the PackInstallerForm
            // So we don't need to provide any handlers for it. 

            if (vsProcess.HasExited)
                errorMessages.Add("Visual Studio exitted after clicking " + buttonName + " button.");
            errorMessages.printErrors("VSActiveCancelTest");
            Assert.AreEqual(0, errorMessages.Count, "VSActiveCancelTest failed. Check Console output for error messages.");
        }

        public void MessageFormButtonClicker()
        {
            ButtonTester messageButtonTester = new ButtonTester(buttonName, messageFormName);
            messageButtonTester.Click();
        }

        public void ProcessButtonHandler(object sender, EventArgs e)
        {
            // Finally, click the Exit button on the PackInstallerForm.          
            ButtonTester buttonTester = new ButtonTester("exitButton", "PackInstallerForm");
            buttonTester.Click();
        }
    }
}
